#pragma once

#include <coroutine>
#include <chrono>
#include <thread>
#include <mutex>
#include <future>

namespace Delay {
class Promise;
class Awaiter;

struct Coroutine {
    using promise_type = Promise;
    
    std::coroutine_handle<promise_type> handle;
    Coroutine(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~Coroutine() {
        if (handle) handle.destroy();
    }
    void resume() {
        if (handle && !handle.done()) handle.resume();
    }
};

class Awaiter {
    std::chrono::duration<double> Duration;
    std::coroutine_handle<Promise> CachedHandle;

    std::future<void>  ThreadFuture;
    std::promise<void> ThreadPromise;
public:
#pragma region Coroutine Interaface
    bool await_ready() const noexcept                                                           { return Duration.count() <= 0; };
    void await_suspend(std::coroutine_handle<Promise> handle);
    void await_resume() noexcept;
#pragma endregion

#pragma region Custom Function
    Awaiter(std::chrono::duration<double> InDuration) : Duration(InDuration)                    {}
    static void async_delay(std::chrono::duration<double> Duration, std::promise<void>& p)      { std::this_thread::sleep_for(Duration); p.set_value(); }
    bool QueryFinished();
#pragma endregion
};

// Special Promise
//     await_transform
class Promise {
private:
    class Awaiter* CurrentAwaiter = nullptr;
public:
#pragma region Coroutine Interface
    Coroutine get_return_object()                   { return Coroutine{ std::coroutine_handle<Promise>::from_promise(*this) }; }
    std::suspend_never initial_suspend()            { return {}; }
    std::suspend_always final_suspend() noexcept    { return {}; }
    void return_void()                              { }
    void unhandled_exception()                      { }
    Awaiter await_transform(double seconds)         { return Awaiter{ std::chrono::duration<double>(seconds) }; }
#pragma endregion

#pragma region Custom Function
    void SetAwaiter(Awaiter* InAwaiter)             { CurrentAwaiter = InAwaiter; }
    bool QueryAwaiterFinished();
#pragma endregion
};

// 函数声明
void Test();
}
